package vma.nicici.chat.history;

import java.io.IOException;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;

import org.apache.http.NameValuePair;

import vma.nicici.chat.communication.AsynchCallback;
import vma.nicici.chat.communication.GetHttpRequest;
import vma.nicici.chat.gson.FbUserInfo;
import vma.nicici.chat.gson.Message;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.util.Log;

import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException;

public class HistoryDatabase {

	private static HistoryDatabase instance = null;
	
	private static final String LOGTAG = "Database";

	private SQLiteDatabase database;
	private DbOpenHelper dbHelper;
	private static final String[] usersColumn = { Contract.UsersEntry._ID,
			Contract.UsersEntry.COLUMN_NAME_FB_USER_ID,
			Contract.UsersEntry.COLUMN_NAME_FIRST_NAME,
			Contract.UsersEntry.COLUMN_NAME_LAST_NAME };

	private static final String[] historyColumn = { Contract.HistoryEntry._ID,
			Contract.HistoryEntry.COLUMN_NAME_FB_USER_ID,
			Contract.HistoryEntry.COLUMN_NAME_TIMESTAMP,
			Contract.HistoryEntry.COLUMN_NAME_MESSAGE_TEXT,
			Contract.HistoryEntry.COLUMN_NAME_LATITUDE,
			Contract.HistoryEntry.COLUMN_NAME_LONGITUDE };

	
	
	private HistoryDatabase(Context context) {
		dbHelper = new DbOpenHelper(context);
	}
	
	public static synchronized HistoryDatabase getInstance() {
		if (instance == null) {
			throw new IllegalStateException("Database not initialized");
		}
		return instance;
	}
	
	public static synchronized HistoryDatabase initialize(Context context) {
		if (instance != null) {
			return instance;
		}
		instance = new HistoryDatabase(context);
		return instance;
	}

	public void open() throws SQLException {
		database = dbHelper.getWritableDatabase();
	}

	public void close() {
		dbHelper.close();
	}

	private ContentValues parseMessage(Message msg) {
		ContentValues values = new ContentValues();
		values.put(Contract.HistoryEntry.COLUMN_NAME_FB_USER_ID,
				msg.facebookUserID);
		values.put(Contract.HistoryEntry.COLUMN_NAME_TIMESTAMP, msg.timestamp);
		values.put(Contract.HistoryEntry.COLUMN_NAME_MESSAGE_TEXT,
				msg.messageText);
		values.put(Contract.HistoryEntry.COLUMN_NAME_LATITUDE, msg.lat);
		values.put(Contract.HistoryEntry.COLUMN_NAME_LONGITUDE, msg.lon);
		return values;
	}

	public long insertMessage(Message msg) {
		long newRowId = database.insert(Contract.HistoryEntry.TABLE_NAME, null,
				parseMessage(msg));
		return newRowId;
	}
	
	public boolean insertMessages(List<Message> messages){
		boolean everythingOK = true;
		for (Message msg : messages) {
			everythingOK &= (insertMessage(msg) != -1L);
		}
		return everythingOK;
	}

	private Message cursorToMessage(Cursor cursor) { 
		int columnIndex = 0; 
		long facebookUserId = cursor.getLong(++columnIndex);
		String timestamp = cursor.getString(++columnIndex);
		String messageTest = cursor.getString(++columnIndex);
		Double lat = cursor.getDouble(++columnIndex);
		Double lon = cursor.getDouble(++columnIndex);
		Message msg = new Message(facebookUserId, timestamp, messageTest, lat,
				lon);
		return msg;
	}

	private ArrayList<Message> cursorToMessageList(Cursor cursor) {
		ArrayList<Message> messages = new ArrayList<Message>();
		cursor.moveToFirst();
		while (!cursor.isAfterLast()) {
			Message newMsg = cursorToMessage(cursor);
			messages.add(newMsg);
			cursor.moveToNext();
		}
		return messages;
	}

	public ArrayList<Message> getAllMessages() {
		String orderBy = Contract.HistoryEntry.COLUMN_NAME_TIMESTAMP + " DESC";

		Cursor cursor = database.query(Contract.HistoryEntry.TABLE_NAME,
				historyColumn, null, null, null, null, orderBy);

		ArrayList<Message> messages = cursorToMessageList(cursor);

		cursor.close();
		return messages;
	}
	

	public ArrayList<Message> getMostRecentMessages(int count){
		String orderBy = Contract.HistoryEntry.COLUMN_NAME_TIMESTAMP + " DESC LIMIT "+ count;

		Cursor cursor = database.query(Contract.HistoryEntry.TABLE_NAME,
				historyColumn, null, null, null, null, orderBy);
		
		ArrayList<Message> messages = cursorToMessageList(cursor);
		cursor.close();
		return messages;
	}

	public ArrayList<Message> getAllMessagesAfterTime(String timestamp) {

		String whereClause = Contract.HistoryEntry.COLUMN_NAME_TIMESTAMP
				+ " > ?";
		String[] whereArgs = { timestamp };
		String orderBy = Contract.HistoryEntry.COLUMN_NAME_TIMESTAMP + " DESC";

		Cursor cursor = database.query(Contract.HistoryEntry.TABLE_NAME,
				historyColumn, whereClause, whereArgs, null, null, orderBy);
		ArrayList<Message> messages = cursorToMessageList(cursor);
		cursor.close();
		return messages;
	}
	
	public ArrayList<Message> getMessagesBeforeTime(String timestamp,int count) {

		String whereClause = Contract.HistoryEntry.COLUMN_NAME_TIMESTAMP
				+ " < ?";
		String[] whereArgs = { timestamp };
		String orderBy = Contract.HistoryEntry.COLUMN_NAME_TIMESTAMP + " DESC LIMIT " + count;

		Cursor cursor = database.query(Contract.HistoryEntry.TABLE_NAME,
				historyColumn, whereClause, whereArgs, null, null, orderBy);
		ArrayList<Message> messages = cursorToMessageList(cursor);
		cursor.close();
		Log.d(LOGTAG,"got " + messages.size() + " before time: " + timestamp);
		return messages;
	}

	private String cursorToUser(Cursor cursor) { 
		int columnIndex = 1;
		String firstname = cursor.getString(++columnIndex);
		String lastname = cursor.getString(++columnIndex);
		return firstname + " " + lastname;
	}

	
	
	public String getName(long facebookUserId) {
		if(facebookUserId < 1 ) {
			return "Anonymous";
		}
		String where = Contract.UsersEntry.COLUMN_NAME_FB_USER_ID + " = '"
				+ facebookUserId + "'";
		Cursor cursor = database.query(Contract.UsersEntry.TABLE_NAME,
				usersColumn, where, null, null, null, null);
		String fullName = "";		
		if (!(cursor.moveToFirst()) || cursor.getCount() == 0 || cursor == null) {
			//ak este user nie je v databaze, tak ho tam pridaj
			fullName = addUser(facebookUserId);
		} else {
			fullName = cursorToUser(cursor);
		}
		cursor.close();
		return fullName;
	}
	
	
	private FbUserInfo getFbUserGson(long facebookUserId) {
		if(facebookUserId < 1 ) {
			return null;
		}
		ArrayList<NameValuePair> emptyParams = new ArrayList<NameValuePair>();
		GetHttpRequest request = new GetHttpRequest(
				"http://graph.facebook.com/" + facebookUserId, emptyParams);
		try {					
			String userJson = request.getStringResponse();
			Gson gson = new Gson();
			FbUserInfo userInfo = gson.fromJson(userJson, FbUserInfo.class);
			return userInfo;
		} catch (IOException e) {
			e.printStackTrace();
			Log.e(LOGTAG, "err", e);
		} catch (URISyntaxException e) {
			e.printStackTrace();
			Log.e(LOGTAG, "err", e);
		} catch (JsonSyntaxException e){
			e.printStackTrace();
		}

		return null;
	}
	
	public void getNameAsynch(final long facebookUserId, final AsynchCallback<String> callback) {
		
		Thread t = new Thread(new Runnable() {
			@Override
			public void run() {
				String result = getName(facebookUserId);
				try {
					
					callback.onFinished(result);
					
				} catch (IOException e) {
					e.printStackTrace();
				} catch (URISyntaxException e) {
					e.printStackTrace();
				}
			}
		});
		
		t.start();
		
	}
	
	public void getFbUserAsynch(final long facebookUserId, final AsynchCallback<FbUserInfo> callback) {
		
		Thread t = new Thread(new Runnable() {
			@Override
			public void run() {
				FbUserInfo result = getFbUserGson(facebookUserId);
				if (result == null) {
					result = new FbUserInfo();
					result.name = "wrong user ID!";
				}
				try {
					
					callback.onFinished(result);
					
				} catch (IOException e) {
					e.printStackTrace();
				} catch (URISyntaxException e) {
					e.printStackTrace();
				}
			}
		});
		
		t.start();
		
	}
	
	private ContentValues parseUser(FbUserInfo userInfo){
		ContentValues values = new ContentValues();
		values.put(Contract.UsersEntry.COLUMN_NAME_FB_USER_ID,
				userInfo.facebookUserID);
		values.put(Contract.UsersEntry.COLUMN_NAME_FIRST_NAME, userInfo.first_name);
		values.put(Contract.UsersEntry.COLUMN_NAME_LAST_NAME, userInfo.last_name);
		return values;
	}
	
	public long insertUser(FbUserInfo userInfo){
		long newRowId = database.insert(Contract.UsersEntry.TABLE_NAME, null,
				parseUser(userInfo));
		return newRowId;		
	}
	

	private String addUser(long facebookUserId) {
		ArrayList<NameValuePair> emptyParams = new ArrayList<NameValuePair>();
		GetHttpRequest request = new GetHttpRequest(
				"http://graph.facebook.com/" + facebookUserId, emptyParams);
		try {			
			
			String userJson = request.getStringResponse();
			Gson gson = new Gson();
			FbUserInfo userInfo = gson.fromJson(userJson, FbUserInfo.class);
			userInfo.facebookUserID = facebookUserId;
			insertUser(userInfo);

			return userInfo.first_name + " " + userInfo.last_name;
			
		} catch (IOException e) {
			e.printStackTrace();
			Log.e(LOGTAG, "err", e);
		} catch (URISyntaxException e) {
			e.printStackTrace();
			Log.e(LOGTAG, "err", e);
		} catch (JsonSyntaxException e){
			e.printStackTrace();
			return "name_error!!";
		}

		return "name_error!!";
	}
	
	public void wipeData(){
		Log.d(LOGTAG, "resetting database - wiping all data");
		dbHelper.onUpgrade(database, 1, 1);
	}
	
	

}
